﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Newtonsoft.Json;
using System.Threading;
using System.Diagnostics;

namespace Gw2Api
{
    public class BaseDiff
    {
        public DateTime ts;
        public string from;
        public string to;
        public BaseDiff()
        {
            ts = DateTime.UtcNow;
        }
    }

    public class BaseApi
    {
        public delegate void UpdateHandler(List<BaseDiff> diff);
        public delegate void ReadyHandler();

        public event UpdateHandler Update;
        public event ReadyHandler Ready;

        private bool _update;
        private bool _refreshing = false;
        private Timer _pollTimer;

        protected Object _lock = new Object();

        public BaseApi(int updateInterval = 5000)
        {
            TimerCallback tcb = this.TimerRefresh;
            _pollTimer = new Timer(tcb, null, 0, updateInterval);
            _update = false;
        }

        ~BaseApi()
        {
            _pollTimer.Dispose();
            _pollTimer = null;
        }

        public virtual void Refresh() { }

        public void TimerRefresh(Object stateInfo)
        {
            if (_refreshing)
                return;
            _refreshing = true;
            if (_update)
            {
                Refresh();
            }
            _refreshing = false;
        }

        public void SetAutoUpdate(bool enabled)
        {
            _update = enabled;
        }

        protected void OnUpdate(List<BaseDiff> diff)
        {
            if (null != Update)
            {
                Update(diff);
            }
        }

        protected void OnReady()
        {
            if (null != Ready)
            {
                Ready();
            }
        }

        protected static string LoadFromUrl(string url)
        {
            string s = "";
            using (WebClient client = new WebClient())
            {
                client.Encoding = Encoding.UTF8;
                bool succeeded = false;
                while (!succeeded)
                {
                    try
                    {
                        Debug.WriteLine("Loading URL: " + url);
                        s = client.DownloadString(url);
                        succeeded = true;
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine(e.ToString());
                    }
                }
            }
            return s;
        }

        struct DownloadInfo
        {
            public LoadFinishedHandler handler;
            public string url;
            public object userdata;
            public DownloadInfo(LoadFinishedHandler h, string u, object d) { this.handler = h; this.url = u; this.userdata = d; }
        }
        protected delegate void LoadFinishedHandler(string data, object userdata);
        protected static void DownloadHandler(object sender, DownloadStringCompletedEventArgs data)
        {
            DownloadInfo di = (DownloadInfo)data.UserState;
            if (null != data.Error)
            {
                LoadFromUrlAsync(di.url, di.handler, di.userdata);
            }
            else
            {
                di.handler(data.Result, di.userdata);
            }
        }
        protected static void LoadFromUrlAsync(string url, LoadFinishedHandler handler, object userdata = null)
        {
            using (WebClient client = new WebClient())
            {
                client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(DownloadHandler);
                client.DownloadStringAsync(new Uri(url), new DownloadInfo(handler, url, userdata));
            }
        }

        protected static T ConvertFromJson<T>(string json)
        {
            return JsonConvert.DeserializeObject<T>(json);
        }
    }
}
